package com.finalministry.db.utils;

import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.CRS;
import org.opengis.geometry.MismatchedDimensionException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.PrecisionModel;
import com.vividsolutions.jts.io.ParseException;
import com.vividsolutions.jts.io.WKTReader;

public class GeoUtils {

	public static final int NONSPHERICAL_MERCATOR_4326 = 4326;
	public static final int SPHERICAL_MERCATOR_900913 = 900913;

	public static Geometry getPointFromCoordinate(Coordinate coordinate) {
		GeometryFactory g = new GeometryFactory(new PrecisionModel(), NONSPHERICAL_MERCATOR_4326);
		Geometry point = g.createPoint(coordinate);
		return point;
	}

	public static Geometry getPointFromText(String coordinateString) throws ParseException {
		Geometry point = new WKTReader(new GeometryFactory(new PrecisionModel(), NONSPHERICAL_MERCATOR_4326)).read(coordinateString);
		return point;
	}

	public static Coordinate getCoordinateFromText(String coordinateString) throws ParseException {
		Geometry point = new WKTReader(new GeometryFactory(new PrecisionModel(), NONSPHERICAL_MERCATOR_4326)).read(coordinateString);
		return point.getCoordinate();
	}

	public static Geometry getGeometryCoordinateFromText(String coordinateString) throws ParseException {
		Geometry point = new WKTReader(new GeometryFactory(new PrecisionModel(), NONSPHERICAL_MERCATOR_4326)).read(coordinateString);
		return point;
	}

	public static Geometry getGeometryFromPolygon(String polygon) throws ParseException {
		Geometry geo = new WKTReader(new GeometryFactory(new PrecisionModel(), NONSPHERICAL_MERCATOR_4326)).read(polygon);
		return geo;
	}

	/**
	 * Transforms a spherical Mercator Point geometry into a non spherical one.
	 * <p>
	 * 
	 * <b>Notes from my previous OpenLayers prototype:</b><br>
	 * 
	 * <pre>
	 * In Openlayers sind die Bounds als EPSG:900913 (spherical Mercator) codiert und muessen erst in 4326 (nur Mercators) umgewandelt werden.
	 * 
	 * 		var point = new OpenLayers.Geometry.Point(16.373056, 48.208333);
	 * 		console.log(point);
	 * 		point.transform(new OpenLayers.Projection("EPSG:4326"),new OpenLayers.Projection("EPSG:900913"));
	 * 		console.log(point);
	 * </pre>
	 * 
	 * @throws FactoryExceptions
	 * @throws NoSuchAuthorityCodeException
	 * @throws TransformException
	 * @throws MismatchedDimensionException
	 */
	public static Geometry transformSphericalToNonspherical(Geometry source) throws Exception {

		CoordinateReferenceSystem sourceCRS = CRS.decode("EPSG:" + NONSPHERICAL_MERCATOR_4326);
		CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:" + SPHERICAL_MERCATOR_900913);

		MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, true);
		Geometry targetGeometry = JTS.transform(source, transform);
		return targetGeometry;
	}

	public static Geometry getNonSphericalFromSpherical(String text) throws Exception {

		Geometry geo = null;
		try {
			geo = new WKTReader(new GeometryFactory(new PrecisionModel(), 900913)).read(text);
		} catch (Exception e) {
			System.out.println(e);
		}

		return transformSphericalToNonspherical(geo);
	}

	public static Geometry transformNonsphericalToSphericalMercator(Geometry source) throws Exception {

		CoordinateReferenceSystem sourceCRS = CRS.decode("EPSG:" + SPHERICAL_MERCATOR_900913);
		CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:" + NONSPHERICAL_MERCATOR_4326);

		MathTransform transform = CRS.findMathTransform(sourceCRS, targetCRS, true);
		Geometry targetGeometry = JTS.transform(source, transform);
		return targetGeometry;
	}

	public static Geometry getSphericalFromNonspherical(String text) throws Exception {
		Geometry geo = new WKTReader(new GeometryFactory(new PrecisionModel(), 4326)).read(text);

		return transformNonsphericalToSphericalMercator(geo);
	}

	public static String getKML_CoordinatesFromPolygon(String nonsphericalPolygonAsText) throws Exception {

		StringBuffer kmlCoordinates = new StringBuffer();
		Geometry geoPolygon = GeoUtils.getSphericalFromNonspherical(nonsphericalPolygonAsText);

		for (Coordinate coordinate : geoPolygon.getCoordinates()) {
			kmlCoordinates.append(coordinate.y);
			kmlCoordinates.append(",");
			kmlCoordinates.append(coordinate.x);
			kmlCoordinates.append("\n");
		}

		return kmlCoordinates.toString();
	}

	public static String getPolygonTextFromBounds(String minlat, String minlon, String maxlat, String maxlon) {

		StringBuffer polygon = new StringBuffer();

		polygon.append("POLYGON ((");
		polygon.append(minlat);
		polygon.append(" ");
		polygon.append(minlon);
		polygon.append(",");
		polygon.append(minlat);
		polygon.append(" ");
		polygon.append(maxlon);
		polygon.append(",");
		polygon.append(maxlat);
		polygon.append(" ");
		polygon.append(maxlon);
		polygon.append(",");
		polygon.append(maxlat);
		polygon.append(" ");
		polygon.append(minlon);
		polygon.append(",");
		polygon.append(minlat);
		polygon.append(" ");
		polygon.append(minlon);

		polygon.append("))");

		return polygon.toString();
	}

}
